// ZIGLAG 指标：基于 MT4 ZigZag 算法的趋势指标
// 参考 TradingView: ZigZag++ by Dev Lucem
// 使用 Depth, Deviation, Backstep 参数

// MT4 ZigZag 算法实现（标准 MT4 逻辑）
// 参考 TradingView ZigZag++ by Dev Lucem
// 返回 { direction, z1, z2, points }
// direction: >0 上升, <0 下降
// z1: 起始点 { barIndex, price }
// z2: 结束点 { barIndex, price }
// points: 所有转折点数组
function calculateMT4ZigZag (dataList, depth = 12, deviation = 5, backstep = 2) {
  if (dataList.length < depth + backstep) {
    return null
  }
  
  // 存储已确认的转折点 [{ barIndex, price, type }]
  const zigzagPoints = []
  let lastHighIndex = -1
  let lastLowIndex = -1
  let lastHighPrice = 0
  let lastLowPrice = 0
  
  // MT4 ZigZag 核心逻辑：从 depth 开始，逐 bar 查找极值点
  for (let i = depth; i < dataList.length; i++) {
    // 查找 depth 范围内的最高点和最低点及其索引
    // 注意：highestbars/lowestbars 返回的是偏移量（负数），0 表示当前 bar
    let highestBarsOffset = 0 // 0 表示当前 bar 是最高点
    let highestPrice = dataList[i].high
    let lowestBarsOffset = 0  // 0 表示当前 bar 是最低点
    let lowestPrice = dataList[i].low
    
    // 在 depth 范围内查找
    for (let j = 1; j < depth; j++) {
      const idx = i - j
      if (idx >= 0 && idx < dataList.length) {
        if (dataList[idx].high > highestPrice) {
          highestPrice = dataList[idx].high
          highestBarsOffset = -j // 负数表示之前的 bar
        }
        if (dataList[idx].low < lowestPrice) {
          lowestPrice = dataList[idx].low
          lowestBarsOffset = -j
        }
      }
    }
    
    // 计算最小价格变化（百分比）
    const minChange = deviation / 100.0
    
    // 获取最后一个转折点（如果存在）
    const lastPoint = zigzagPoints.length > 0 ? zigzagPoints[zigzagPoints.length - 1] : null
    const lastType = lastPoint ? lastPoint.type : null
    
    // pH: 当前 bar 是最高点
    const pH = (highestBarsOffset === 0) ? highestPrice : null
    // pL: 当前 bar 是最低点
    const pL = (lowestBarsOffset === 0) ? lowestPrice : null
    
    if (lastPoint === null) {
      // 初始化：选择第一个极值点（优先选择高点）
      if (pH !== null) {
        zigzagPoints.push({
          barIndex: i,
          price: pH,
          type: 'high'
        })
        lastHighIndex = i
        lastHighPrice = pH
      } else if (pL !== null) {
        zigzagPoints.push({
          barIndex: i,
          price: pL,
          type: 'low'
        })
        lastLowIndex = i
        lastLowPrice = pL
      }
    } else if (lastType === 'high') {
      // 上一个转折点是高点，现在寻找低点（转折）或更高的高点（更新）
      
      // 检查是否有新的高点（更新当前高点）
      if (pH !== null && pH > lastHighPrice) {
        // 检查是否满足最小变化要求（相对于上一个低点）
        const lastLow = zigzagPoints.length >= 2 ? zigzagPoints[zigzagPoints.length - 2] : null
        if (lastLow && (pH - lastLow.price) / lastLow.price >= minChange) {
          // 检查 backstep：确保新点与上一个点的距离足够
          if (zigzagPoints.length === 1 || i - zigzagPoints[zigzagPoints.length - 2].barIndex >= backstep) {
            // 更新最后一个高点
            zigzagPoints[zigzagPoints.length - 1] = {
              barIndex: i,
              price: pH,
              type: 'high'
            }
            lastHighIndex = i
            lastHighPrice = pH
          }
        }
      }
      
      // 检查是否有新的低点（转折点）
      if (pL !== null && lastHighPrice && (lastHighPrice - pL) / lastHighPrice >= minChange) {
        // 检查 backstep
        if (i - lastPoint.barIndex >= backstep) {
          zigzagPoints.push({
            barIndex: i,
            price: pL,
            type: 'low'
          })
          lastLowIndex = i
          lastLowPrice = pL
        }
      }
    } else if (lastType === 'low') {
      // 上一个转折点是低点，现在寻找高点（转折）或更低的低点（更新）
      
      // 检查是否有新的低点（更新当前低点）
      if (pL !== null && pL < lastLowPrice) {
        // 检查是否满足最小变化要求（相对于上一个高点）
        const lastHigh = zigzagPoints.length >= 2 ? zigzagPoints[zigzagPoints.length - 2] : null
        if (lastHigh && (lastHigh.price - pL) / lastHigh.price >= minChange) {
          // 检查 backstep
          if (zigzagPoints.length === 1 || i - zigzagPoints[zigzagPoints.length - 2].barIndex >= backstep) {
            // 更新最后一个低点
            zigzagPoints[zigzagPoints.length - 1] = {
              barIndex: i,
              price: pL,
              type: 'low'
            }
            lastLowIndex = i
            lastLowPrice = pL
          }
        }
      }
      
      // 检查是否有新的高点（转折点）
      if (pH !== null && lastLowPrice && (pH - lastLowPrice) / lastLowPrice >= minChange) {
        // 检查 backstep
        if (i - lastPoint.barIndex >= backstep) {
          zigzagPoints.push({
            barIndex: i,
            price: pH,
            type: 'high'
          })
          lastHighIndex = i
          lastHighPrice = pH
        }
      }
    }
  }
  
  // 返回最后两个点（z1, z2）和当前方向
  if (zigzagPoints.length >= 2) {
    const z1 = zigzagPoints[zigzagPoints.length - 2]
    const z2 = zigzagPoints[zigzagPoints.length - 1]
    const direction = z2.type === 'high' ? 1 : -1
    return {
      direction,
      z1: { barIndex: z1.barIndex, price: z1.price },
      z2: { barIndex: z2.barIndex, price: z2.price },
      points: zigzagPoints
    }
  } else if (zigzagPoints.length === 1) {
    const z2 = zigzagPoints[0]
    const direction = z2.type === 'high' ? 1 : -1
    return {
      direction,
      z1: null,
      z2: { barIndex: z2.barIndex, price: z2.price },
      points: zigzagPoints
    }
  }
  
  return null
}

// 计算 ZIGLAG 指标值（兼容旧接口）
function calculateZIGLAG (dataList, depth = 12, deviation = 5, backstep = 2) {
  const result = calculateMT4ZigZag(dataList, depth, deviation, backstep)
  if (!result) {
    return { swingPoints: [], zigValues: [] }
  }
  
  // 转换为旧格式的 swingPoints
  const swingPoints = result.points.map((p, idx) => ({
    type: p.type === 'high' ? 'high' : 'low',
    value: p.price,
    index: idx,
    barIndex: p.barIndex
  }))
  
  // 构建 ZIG ZAG 折线数据
  const zigValues = []
  let lastZigValue = null
  
  for (let i = 0; i < dataList.length; i++) {
    const point = swingPoints.find(p => p.barIndex === i)
    if (point) {
      lastZigValue = point.value
      zigValues.push({
        zig: lastZigValue,
        swingType: point.type,
        swingIndex: point.index
      })
    } else {
      zigValues.push({
        zig: lastZigValue,
        swingType: null,
        swingIndex: null
      })
    }
  }
  
  return { swingPoints, zigValues, direction: result.direction, z1: result.z1, z2: result.z2 }
}

// 计算 ZIG ZAG 的 swing points（保留旧函数以兼容）
function calculateZigZagSwingPoints (dataList, depth = 12, deviation = 5, backstep = 2) {
  const result = calculateMT4ZigZag(dataList, depth, deviation, backstep)
  if (!result) {
    return []
  }
  
  return result.points.map((p, idx) => ({
    type: p.type === 'high' ? 'high' : 'low',
    value: p.price,
    index: idx,
    barIndex: p.barIndex
  }))
}

// 计算几何平均（保留以兼容）
function calculateGeometricAverage (values, alpha = 0.01, len = 20) {
  if (!values || values.length === 0) return null
  
  const buf = []
  for (const val of values) {
    if (val !== null && !isNaN(val)) {
      buf.push(val)
      if (buf.length > len) {
        buf.shift()
      }
    }
  }
  
  if (buf.length === 0) return null
  
  let wsum = 0.0
  let lsum = 0.0
  
  for (let i = 0; i < buf.length; i++) {
    const p = buf[buf.length - 1 - i] // 最新的在前
    const F = 1.0 + p / 100.0 // factor
    if (F > 0) {
      const w = alpha * Math.pow(1 - alpha, i)
      lsum += Math.log(F) * w
      wsum += w
    }
  }
  
  return wsum > 0 ? (Math.exp(lsum / wsum) - 1.0) * 100.0 : null
}

const zigLagIndicator = {
  name: 'ZIGLAG',
  shortName: 'ZIGLAG',
  calcParams: [12, 5, 2], // depth, deviation, backstep
  figures: [
    { key: 'zig', title: 'ZIG: ', type: 'line' }
  ],
  calc: (dataList, indicator) => {
    const params = indicator.calcParams || [12, 5, 2]
    const { zigValues } = calculateZIGLAG(dataList, params[0], params[1], params[2])
    return zigValues.map(v => ({ zig: v.zig }))
  },
  styles: (indicator, defaultStyles, figureKey, result) => {
    if (figureKey === 'zig') {
      return {
        ...defaultStyles,
        line: {
          ...defaultStyles.line,
          color: '#6ba583',
          size: 2
        }
      }
    }
    return defaultStyles
  }
}

export default zigLagIndicator
export { calculateZIGLAG, calculateZigZagSwingPoints, calculateGeometricAverage, calculateMT4ZigZag }
